//
//  TinyHttpd.m
//  TruncationDetector
//
//  Created by Taodong Lu on 8/16/15.
//  Copyright (c) 2015 Taodong Lu. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "TinyHttpd.h"
@interface TinyHttpd()
{
    BOOL requestHTML;
    BOOL requestJson;
}

@end

@implementation TinyHttpd

/* http://<url>/html/report */
/* http://<url>/json/report */
- (id) initWithData:(NSData* )data
{
    requestHTML = false;
    requestJson = false;
    headers = [[NSMutableArray alloc] initWithCapacity:1];
    if (data == nil) {
        return self;
    }
    NSString* request = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSArray* lines = [request componentsSeparatedByString: @"\n"];
    NSString* methods = [lines objectAtIndex: 0];
    NSArray* methodTokens = [methods componentsSeparatedByString: @" "];
    if ([methodTokens count] != 3) {
        assert(0);
        return self;
    }
    method = [methodTokens objectAtIndex: 0];
    uri = [methodTokens objectAtIndex: 1];
    if (uri != nil && [uri compare: @"/html/report" options: NSCaseInsensitiveSearch] == 0) {
        requestHTML = true;
    } else if (uri != nil && [uri compare: @"/json/report" options: NSCaseInsensitiveSearch] == 0) {
        requestJson = true;
    }
    
    NSLog(@"Request Method: %@", method);
    NSLog(@"Request URI: %@", uri);
    NSLog(@"Request Version: %@", [methodTokens objectAtIndex: 2]);
    
    return self;
}

- (BOOL) isValid
{
    if (method != nil && [method compare: @"GET" options: NSCaseInsensitiveSearch] == 0 &&
       (requestHTML == true || requestJson == true)) {
        return true;
    }
    return false;
}
- (BOOL) isRequestHtml
{
    return requestHTML;
}
- (NSData *) error
{
    assert(![self isValid]);
    NSString* err = @"Please check http protocol";
    [self beginHeader: 400 withTitle: @"Bad Request"];
    [self addHeader:@"Content-Type" withValue: @"text/plain"];
    [self addHeader:@"Content-Length" withValue: [NSString stringWithFormat: @"%lu", err.length]];
    NSString* header = [self endHeader];
    NSMutableData* data = [[NSMutableData alloc] initWithData: [header dataUsingEncoding: NSUTF8StringEncoding]];
    [data appendData: [err dataUsingEncoding: NSUTF8StringEncoding]];
    return data;
}

- (NSData *) success
{
    assert([self isValid]);
    NSString* success = @"success";
    [self beginHeader: 204 withTitle: @"No Content"];
    [self addHeader:@"Content-Type" withValue: @"text/plain"];
    [self addHeader:@"Content-Length" withValue: [NSString stringWithFormat: @"%lu", success.length]];
    NSString* header = [self endHeader];
    NSMutableData* data = [[NSMutableData alloc] initWithData: [header dataUsingEncoding: NSUTF8StringEncoding]];
    [data appendData: [success dataUsingEncoding: NSUTF8StringEncoding]];
    return data;
}

- (NSData *) success: (NSData *)remoteData
{
    assert([self isValid]);
    if (remoteData == nil) {
        return [self success];
    }
    [self beginHeader: 200 withTitle: @"OK"];
    if (requestHTML)
        [self addHeader:@"Content-Type" withValue: @"text/html"];
    else
        [self addHeader:@"Content-Type" withValue: @"application/json"];
    [self addHeader:@"Content-Length" withValue: [NSString stringWithFormat: @"%lu", [remoteData length]]];
    NSString* header = [self endHeader];
    NSMutableData* data = [[NSMutableData alloc] initWithData: [header dataUsingEncoding: NSUTF8StringEncoding]];
    [data appendData: remoteData];
    return data;
}

- (void) beginHeader: (int)code withTitle:(NSString*)title
{
    if ([headers count] > 0)
        return;
    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
    NSTimeZone* gmt = [NSTimeZone timeZoneWithAbbreviation: @"GMT"];
    [dateFormatter setTimeZone: gmt];
    dateFormatter.dateFormat = @"EEE, dd MMM yyyy HH:mm:ss zzz";
    NSString* status = [NSString stringWithFormat: @"%s %d %@\r\n", "HTTP/1.1", code, title];
    [headers addObject:status];
    NSString* now = [NSString stringWithFormat: @"Date: %@\r\n", [dateFormatter stringFromDate: [NSDate date]]];
    [headers addObject: now];
}

- (void) addHeader: (NSString*)catalog withValue: (NSString*)value
{
    NSString* content = [NSString stringWithFormat: @"%@: %@\r\n", catalog, value];
    [headers addObject: content];
}

- (NSString*) endHeader
{
    NSString* end = @"\r\n";
    [headers addObject: end];
    NSString* result = [[headers valueForKey:@"description"] componentsJoinedByString: @""];
    return result;
}
@end